package cc.eddic.examinationsystem.core;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import lombok.val;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static cc.eddic.examinationsystem.core.RequestUtils.*;


/**
 * REST API 错误
 */
@Getter
@Slf4j
public class RestError {

    /**
     * URL 路径
     */
    private final String path;

    /**
     * 时间戳
     */
    private final LocalDateTime timestamp;

    /**
     * 错误信息
     */
    private final String message;

    /**
     * StackTrace
     */
    private final String trace;

    private final List<FieldError> fieldErrors;

    public RestError(String path, LocalDateTime timestamp, String message, String trace, List<FieldError> fieldErrors) {
        this.path = path;
        this.timestamp = timestamp;
        this.message = message;
        this.trace = trace;

        this.fieldErrors = null != fieldErrors && fieldErrors.isEmpty() ? null : fieldErrors;
    }

    public static String msg(HttpServletRequest request, String message) {
        return String.format("%s, URL=%s, IP=%s, UA=%s", message, getFullUrl(request), getRequestIp(request), getUserAgent(request));
    }

    public static String msg(HttpServletRequest request, Exception ex) {
        return msg(request, ex.getMessage());
    }

    public static RestError of(HttpServletRequest request, String message) {
        log.warn(msg(request, message));
        return new RestError(getFullUrl(request), LocalDateTime.now(), message, null, new ArrayList<>());
    }

    public static RestError of(HttpServletRequest request, String message, List<FieldError> fieldErrors) {
        log.warn(msg(request, message));
        return new RestError(getFullUrl(request), LocalDateTime.now(), message, null, fieldErrors);
    }

    public static RestError of(HttpServletRequest request, Exception ex) {
        return of(request, ex, new ArrayList<>());
    }

    public static RestError of(HttpServletRequest request, Exception ex, List<FieldError> fieldErrors) {
        log.warn(msg(request, ex), ex);
        return new RestError(getFullUrl(request), LocalDateTime.now(), ex.getMessage(), null, fieldErrors);
    }

    public static RestError ofWithStackTrace(HttpServletRequest request, Exception ex) {
        return ofWithStackTrace(request, ex, new ArrayList<>());
    }

    public static RestError ofWithStackTrace(HttpServletRequest request, Exception ex, List<FieldError> fieldErrors) {
        log.warn(msg(request, ex), ex);
        return new RestError(getFullUrl(request), LocalDateTime.now(), ex.getMessage(), stackTrace(ex), fieldErrors);
    }

    private static String stackTrace(Exception ex) {
        StringWriter stackTrace = new StringWriter();
        ex.printStackTrace(new PrintWriter(stackTrace));
        stackTrace.flush();

        val str = stackTrace.toString();

        try {
            stackTrace.close();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return str;
    }
}
